package flex.cc.order.manage.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import flex.cc.PublicUtil;
import flex.cc.base.dto.LoginAuthDto;
import flex.cc.basicinformation.entity.ChannelDataEntity;
import flex.cc.common.Constants;
import flex.cc.common.utils.CommonUtils;
import flex.cc.common.utils.HttpClientUtil;
import flex.cc.core.utils.RequestUtil;
import flex.cc.order.manage.dao.OrderTrackDao;
import flex.cc.order.manage.dto.order.OrderMainEntity;
import flex.cc.order.manage.dto.order.OrderTrackEntity;
import flex.cc.system.entity.DictCodeEntity;
import flex.cc.system.service.DictCodeService;
import flex.cc.util.EncryptionDecryption;
import flex.cc.vehicle_svr.model.SynStatusModel;
import flex.cc.util.DateUtil;

/**
 * 
 * @author WANGCONG
 * 2022年1月5日下午13:28:52
 * @desc 异步回调上游取消接口
 *  实现AsyncConfigurer的配置类只能有一个
 */
@Service
@EnableAsync
public class AsyncUpCancellService implements AsyncConfigurer{

	private static final Logger logger = LoggerFactory.getLogger(AsyncUpCancellService.class);
	@Autowired
    private OrderTrackDao orderTrackDao;
	@Resource
	private DictCodeService dictCodeService;
	
	/**
	 * 
	 * @param channelDataList 渠道接口地址集合
	 * @param statusVo  下游回写报文
	 * @param orderMain 服务单主表信息
	 * @param salvationStatus 回写上游状态
	 * @param cancelChannel 取消渠道：1-上游，2-下游，3-车服，4-C端（上游和车服的，不会走这个方法）
	 */
	@SuppressWarnings("static-access")
	@Async
	public void asyncCancell(List<ChannelDataEntity> channelDataList, SynStatusModel statusVo,
			OrderMainEntity orderMain, String salvationStatus, String cancelChannel) {
		logger.info("---------------------AsyncCancellService.asyncCancell状态回写触发：异步回调上游取消接口---------------------");
		String cancelNotice_url = "";
		for(int j=0; j<channelDataList.size(); j++){
			if(Constants.cancelRescue.equals(channelDataList.get(j).getUrlType())){
				cancelNotice_url = channelDataList.get(j).getUrl();
   			break;
   		}
		}
		if(PublicUtil.isEmpty(cancelNotice_url)){
			saveTrack(orderMain.getOrderNo(), "03", "回调上游取消通知失败：地址未配置", orderMain.getStatus(), new Date(), RequestUtil.getLoginUser());
		}else{
			Date cancelTime = new Date();
			/**
			 * cancelMsg：取消有费用+客户自解传1；取消无费用+客户自解传2；其他对应传值5、8、13
			 * cancelCode：取消有费用+客户自解传1；取消无费用+客户自解传2；其他对应传值5、8、13
			 * 1-客户自解产生空驶费
			 * 2-客户自解未产生空驶费
			 * 5-事故救援
			 * 8-高速公路救援
			 * 13-其他
			 */
			String cancelType = statusVo.getCancelType();//01-客户自解；02-高速救援；03-事故救援；99-其他
			String cancelCode = "13";
			String cancelMsg = "其他";
			if(cancelChannel.equals("4")){ //C端取消都是客户自解
				cancelType = "01";
			}
			if(cancelType.equals("01")){
				if("CANCEL_COST".equals(salvationStatus)){//取消有费用+客户自解
					cancelCode = "1";
					cancelMsg = "客户自解产生空驶费";
				}else{
					cancelCode = "2";
					cancelMsg = "客户自解未产生空驶费";
				}
			}else if(cancelType.equals("02")){
				cancelCode = "8";
				cancelMsg = "高速公路救援";
			}else if(cancelType.equals("03")){
				cancelCode = "5";
				cancelMsg = "事故救援";
			}
			//计算服务类型服务金额：救援金额---按服务类型配置*50%
			String serviceAmount = "0";
			Map<String, Object> codeParams = new HashMap<String, Object>();
			codeParams.put("code", orderMain.getServiceItem());
			codeParams.put("typeCode", "serviceItem");
			DictCodeEntity codeVo = dictCodeService.getOneByParams(codeParams);
			if(codeVo!=null && PublicUtil.isNotEmpty(codeVo.getValue1())){
				int tempVal = Integer.parseInt( codeVo.getValue1().split("\\.")[0] );
				serviceAmount = tempVal/2+"";
			}
			Map<String, Object> body = new HashMap<String, Object>();
			Map<String, String> requestHeader = new HashMap<String, String>();
			Map<String, String> requestBody = new HashMap<String, String>();
			requestHeader.put("partnerCode", CommonUtils.PARTNERCODE);
			requestHeader.put("clientId", CommonUtils.CLIENTID);
			requestHeader.put("requestCode", "RescuerRequestCancel");
			body.put("requestHeader", requestHeader);
			requestBody.put("ownerOrderNo", orderMain.getOwnerOrderNo());
			requestBody.put("salvationStatus", salvationStatus);
			requestBody.put("serviceAmount", serviceAmount);
			requestBody.put("cancelReason", cancelChannel.equals("4") ? "客户自主发起取消" : PublicUtil.isNotEmpty(statusVo.getCancelReason()) ? statusVo.getCancelReason() : "取消" );
			requestBody.put("cancelTime", DateUtil.DateToString(cancelTime));
			requestBody.put("cancelMsg", cancelMsg); //取消状态说明
			requestBody.put("cancelCode", cancelCode);//取消状态代码
			requestBody.put("totalDistance", "0"); //预计总行程距离（单位：m）,暂定传0
			//已行驶距离,取vainDistance的值
			System.out.println("----statusVo.getVainDistance()取值前----");
			requestBody.put("usedDistance", PublicUtil.isNotEmpty(statusVo.getVainDistance()) ? ""+statusVo.getVainDistance() : "0");
			System.out.println("----statusVo.getVainDistance()取值后----");
			requestBody.put("elapsedTime", DateUtil.getDateSecond(orderMain.getCreateTime(), cancelTime)+"");
			body.put("requestBody", requestBody);
			AtomicReference<Integer> counter = new AtomicReference<Integer>(0);
			String temp_code = ""; //记录接口回写的code码，便于轨迹备注插入
			while(counter.get()<3){
				try {
					EncryptionDecryption des = new EncryptionDecryption();
					String jsonStr = JSON.toJSONString(body);
					System.out.println("加密前的取消通知报文=" + jsonStr);
					String jsonBody = des.encrypt(jsonStr);
					System.out.println("加密后的取消通知报文=" + jsonBody);
					String result = HttpClientUtil.sendHttpPost(cancelNotice_url, jsonBody, null);
					System.out.println("渠道商取消通知返回响应加密报文=" + result);
					if (result != null) {
						result = des.decrypt(result.trim(), "UTF-8");
						System.out.println("渠道商取消通知返回响应解密报文=" + result);
						JSONObject resultObj = JSONObject.parseObject(result);
	        			// 0：正常；非0都为异常；异常超时增加9999状态码
	                    String resultCode = PublicUtil.isNotEmpty(resultObj.get("responseCode")) ? resultObj.get("responseCode").toString() : null; 
	                    temp_code = resultCode;
	                    if(PublicUtil.isNotEmpty(resultCode) && "9999".equals(resultCode)){
	                    	counter.compareAndSet(counter.get(), counter.get()+1);
	                    }else{
	                    	counter.getAndSet(5);
	                    }
					}else {
	            		counter.compareAndSet(counter.get(), counter.get()+1);
	            	}
				} catch (Exception e) {
					//请求上游取消通知接口异常
					counter.getAndSet(5);
				}
			}
			//渠道商取消通知返回响应解密报文={"responseCode":"00","responseMsg":"成功!!"}
			if("00".equals(temp_code)){//成功
				//插入成功的调用上游取消轨迹
				saveTrack(orderMain.getOrderNo(), "03", "回调上游取消通知成功", orderMain.getStatus(), new Date(), RequestUtil.getLoginUser());
			}else{
				if("9999".equals(temp_code)){//超时异常
					saveTrack(orderMain.getOrderNo(), "03", "回调上游取消通知失败：请求超时", orderMain.getStatus(), new Date(), RequestUtil.getLoginUser());
				}else{//失败
					saveTrack(orderMain.getOrderNo(), "03", "回调上游取消通知失败", orderMain.getStatus(), new Date(), RequestUtil.getLoginUser());
				}
			}
		}
	}
	
	private void saveTrack(String orderNo, String trackType, String trackDesc, String status, Date currentDate, LoginAuthDto loginUser){
        // 服务单轨迹表
        OrderTrackEntity orderTrackEntity = new OrderTrackEntity();
        orderTrackEntity.setDataId(UUID.randomUUID().toString().replace("-", ""));
        orderTrackEntity.setOrderNo(orderNo);
        orderTrackEntity.setTrackType(trackType);
        orderTrackEntity.setTrackDesc(trackDesc);
        orderTrackEntity.setStatus(status);
        orderTrackEntity.setIsDelete(0);
        orderTrackEntity.setCreateTime(currentDate);
        orderTrackEntity.setCreater(loginUser.getUserCode());
        orderTrackEntity.setUpdateTime(currentDate);
        orderTrackEntity.setUpdater(loginUser.getUserCode());
        orderTrackDao.insert(orderTrackEntity);
    }
	
	// 注册执行器
	//解决：No qualifying bean of type 'org.springframework.core.task.TaskExecutor' available: expected single matching bean but found 2: applicationTaskExecutor,taskScheduler
	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setCorePoolSize(10);
		taskExecutor.setMaxPoolSize(80);
		taskExecutor.setQueueCapacity(100);
		taskExecutor.initialize();// 如果不初始化，导致找到不到执行器
		return taskExecutor;
	}

	// 用于捕获异常
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		System.out.println("B异常了");
		return null;
	}
}
